<?php
/**
 * Глобальный контроллер
 * 
 * @category Phorm
 * @package Controller
 * @name /Phorm/Controller/Controller.php
 * @copyright phorm.ru
 * @since 22.11.2010
 * @author vladimir@kachalov.net
 */
class Phorm_Controller_Controller extends Zend_Controller_Action {
	
	/**
	 * Объект загрузки приложения
	 * @var Phorm_Bootstrap
	 */
	protected $_boot;
	
	/**
	 * Параметры запроса
	 * @var array
	 */
	protected $_params;
	
	/**
	 * Массив конфигурации приложения
	 * @var array
	 */
	protected $_cnf;
	
	/**
	 * Объект пользовательской сессии
	 * @var Zend_Session_Abstract
	 */
	protected $_usersession;
	
	/**
	 * Объект переводчика
	 * @var Zend_Translate
	 */
	protected $_translate;
	
	
	/**
	 * Инициализация контроллера
	 * 
	 * @return void
	 */
	
	public function init() {

		/**
		 * Вытаскиваем ресурсы из реестра загрузки
		 */
		
		$this->_boot = $this->getInvokeArg('bootstrap');
		$this->_cnf = $this->_boot->getOptions();
		$this->_params = $this->_request->getParams();
		$this->_usersession = $this->_boot->getResource('UserSession');
		$this->_translate = $this->_boot->getResource('Translate');
		
		/**
		 * Переопределяем информацию об MVC-ресурсе в случае перенаправлений (форвардов)
		 */
		
		if(!isset($this->_params['mvcinfo']) || (
				  $this->_params['mvcinfo']['module']!=$this->_params['module'] ||
				  $this->_params['mvcinfo']['controller']!=$this->_params['controller'] ||
				  $this->_params['mvcinfo']['action']!=$this->_params['action'])) {	 	
				 	
			$Mvc = new Phorm_Mvc();
			$this->_params['mvcinfo'] = $Mvc->getCurrentMvcInfo();
			
			$this->_setParam('WidgetSetId',$this->_params['mvcinfo']['widgetssetid']);
			$this->_setParam('mvcinfo',$this->_params['mvcinfo']);
			
			$this->_params['isfwd'] = true;
		}
		
		//print_r($this->_request->getParams());
    	
    }
    
    
    /**
     * Dispatch the requested action
     *
     * @param string $action Method name of action
     * @return void
     */
    public function dispatch($action) {

        $this->_helper->notifyPreDispatch();
        
		if(!$this->isAllow()) {
			
        	return $this->_forward('forbidden','error','default',array('action'=>'forbidden','controller'=>'error','module'=>'default'));
        	
        } else {
        	
        	// Передаем в объект View информацию об MVC-ресурсе 
			// до диспетчеризации, чтобы ее можно было переписать в контроллерах
			$this->setViewMvc();
        	
			$this->prePhormDispatch(); 
        	$this->preDispatch();
        	
        }
        
        if ($this->getRequest()->isDispatched()) {
        	
            if (null === $this->_classMethods) $this->_classMethods = get_class_methods($this);

            // preDispatch() didn't change the action, so we can continue
            if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
            	
                if ($this->getInvokeArg('useCaseSensitiveActions')) {
                    trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
                }
                
				$this->$action();

            } else {
            	
                $this->__call($action, array());
                
            }
            
            $this->postDispatch();
            $this->postPhormDispatch(); 
            
        }

        // whats actually important here is that this action controller is
        // shutting down, regardless of dispatching; notify the helpers of this
        // state
        $this->_helper->notifyPostDispatch();
    }
    
    
    /**
	 * Локальный предиспетчер (возможность переписать стандартный предиспетчер оставляем разработчику)
	 * 
	 * @return void
	 */
		
	protected function prePhormDispatch() {
		
		/**
		 * Отображение сообщений из сессии
		 * Необходимо для форм, чтобы сделать редирект и избежать даблпоста
		 * Использование:
		 * 		$this->_usersession->SuccessMessage = 'Выбранное действие успешно совершено';
		 * 		return $this->_redirect('/какой-то-урл');
		 * 		или через метод враппер $this->composeSuccessMessage('Выбранное действие успешно совершено','/путь без siteUrl')
		 * @see self::composeSuccessMessage
		 * @see self::composeErrorMessage
		 */
		
		if(isset($this->_usersession->SuccessMessage)) {
			$this->view->assign('Success',is_array($this->_usersession->SuccessMessage) ? $this->_usersession->SuccessMessage : array($this->_usersession->SuccessMessage));
			unset($this->_usersession->SuccessMessage);
		}
		
		if(isset($this->_usersession->ErrorMessage)) {
			$this->view->assign('Errors',is_array($this->_usersession->ErrorMessage) ? $this->_usersession->ErrorMessage : array($this->_usersession->ErrorMessage));
			unset($this->_usersession->ErrorMessage);
		}
		
	}
    
    
    /**
	 * Локальный постдиспетчер (возможность переписать стандартный постдиспетчер оставляем разработчику)
	 * 
	 * @return void
	 */
		
	protected function postPhormDispatch() {
		
		// Передаем в объект View объект конфигурации и текущие параметры
		$this->setViewOther();
		
		// Загружаем виджеты
		$this->loadWidgets();
		
		// Загружаем профайлер БД
		$this->setProfiler();
		
	}
	
	
	/**
	 * Загрузка виджетов
	 * 
	 * @return void
	 * @todo Надо еще возвращать код макета layoutname
	 */
		
	protected function loadWidgets() {
			
		if(!isset($this->_cnf['phorm']['widgets']) || $this->_cnf['phorm']['widgets']==true) {
		
			if($this->_getParam('WidgetSetId')>0) {
						
				$Widgets = new Phorm_Widget_Loader();
				$this->view->assign('Layouts',$Widgets->getLayouts());
								
			}
		
		}
		    		
	}
	
	
	/**
	 * Загрузка профайлера базы данных
	 * 
	 * @return void
	 */
		
	protected function setProfiler() {
			
		if($this->_cnf['resources']['db']['params']['profiler']) {
			
			$profiler = $this->_boot->getResource('Db')->getProfiler();
	    	$this->view->assign('SqlTotal',$profiler->getTotalElapsedSecs());
			$this->view->assign('SqlQueries',$profiler->getTotalNumQueries());
			
			//print_r($profiler);
			
		}
		    		
	}
	
	
	/**
	 * Передача в объект View данных об MVC-ресурсе
	 * 
	 * @return void
	 */
		
	protected function setViewMvc() {
		
		$this->view->headTitle($this->_translate->_(empty($this->_params['mvcinfo']['seotitle']) ? $this->_params['mvcinfo']['resourcename'] : $this->_params['mvcinfo']['seotitle']));
		$this->view->headMeta() -> appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8')
								-> appendName('keywords', $this->_translate->_((string)$this->_params['mvcinfo']['seokeywords']))
								-> appendName('description', $this->_translate->_((string)$this->_params['mvcinfo']['seodescription']))
								-> appendName('generator', 'Phorm.CMS');
		$this->view->assign('Header',$this->_translate->_($this->_params['mvcinfo']['resourcename']));
		$this->view->assign('MvcInfo',$this->_params['mvcinfo']);
		
		$mvcinfo = array(
			'module' => $this->_params['module'],
			'controller' => $this->_params['controller'],
			'action' => $this->_params['action']
		);
		$params = $this->_params;
		unset($params['mvcinfo']);
		$this->view->JQuery()->addJavascript('var mvcinfo=' . ZendX_JQuery::encodeJson($mvcinfo + $params) . ';');
		    		
	}
	
	
	/**
	 * Передача в объект View дополнительных переменных
	 * 
	 * @return void
	 */
		
	protected function setViewOther() {
			
		$this->view->assign('cnf',$this->_cnf);
		$this->view->assign('params',$this->_params);
		$this->view->assign('translate',$this->_translate);
		$this->view->assign('UserData',$this->_usersession->UserData);
		$this->view->assign('Acl',$this->_usersession->UserData['acl']);
		//$this->view->assign('Navigation',$this->_boot->getResource('Navigation'));
   		
	}
	
	
	/**
	 * Проверяет, имеет ли пользователь доступ к текущей странице на основе параметров запроса
	 * 
	 * @return boolean
	 */
		
	protected function isAllow() {
			
		// Проверяем доступ к MVC-компоненте
		if(!isset($this->_usersession->UserData['acl']['mvc'][$this->_params['module']][$this->_params['controller']][$this->_params['action']])) {
			return false;
		}
		
		// При форвардах игнорируем проверку доступа к разделу и материалу
		if(isset($this->_params['isfwd']) && $this->_params['isfwd']==true) return true;
		
		// Проверяем доступ к разделу
		if(isset($this->_params['categoryinfo'])) {
			if($this->_usersession->UserData['acl']['categories'][$this->_params['categoryinfo']['categoryid']]<=200) {
				return false;
			}
		}
		
		// Проверяем доступ к материалу
		if(isset($this->_params['resourceinfo'])) {
			$Resource = new Phorm_Resource();
			return $Resource->isAllowedAction('view',$this->_params['categoryinfo']['categoryid'],$this->_params['resourceinfo']['creator']);
		}
		
		return true;
		    		
	}
	
	
	/**
	 * Передает в шаблон сообщение об ошибке при неудачной SQL-трансакции в зависимости от текущего окружения
	 *
	 * @param mixed $message Текст сообщения или массив текстов (трейс ошибок)
	 * @return true
	 * @todo Добавить отправку письма администратору или логирование ошибок
	 */
	
	protected function composeTransactionErrorMessage($message) {
		
		$this->view->assign('Errors',
			APPLICATION_ENV == 'development' ? 
				$message : array($this->_translate->_('Не удалось сохранить данные. Попробуйте еще раз')));
				
		return true;
		
	}
	
	/**
	 * Передает в шаблон сообщение об ошибке при неудачной попытке удаления в зависимости от текущего окружения
	 *
	 * @param mixed $message Текст сообщения или массив текстов (трейс ошибок)
	 * @param string $redirect Путь для переадресации без siteUrl (если не указан, редирект происходит по рефереру)
	 * @return true
	 * @todo Добавить отправку письма администратору или логирование ошибок
	 */
	
	protected function composeDeleteErrorMessage($message, $redirect = null) {
		
		$message = APPLICATION_ENV == 'development' ? 
					$message : array($this->_translate->_('Не удалось удалить запись. Попробуйте еще раз'));
					
		return $this->composeErrorMessage($message,$redirect);
		
	}
	
	/**
	 * Устанавливает успешное сообщение в сессию пользователя и производит переадресацию по указанному адресу
	 *
	 * @param string $message Текст сообщения
	 * @param string $redirect Путь для переадресации без siteUrl (если не указан, редирект происходит по рефереру)
	 * @return true
	 */
	
	protected function composeSuccessMessage($message = 'Данные успешно сохранены', $redirect = null) {
		
		$this->_usersession->SuccessMessage = $this->_translate->_($message);
		
		return is_null($redirect) 
				? $this->_redirect($this->_request->getServer('HTTP_REFERER'))
				: $this->_redirect($this->view->siteUrl().$redirect);
		
	}
	
	/**
	 * Устанавливает сообщение об ошибке в сессию пользователя и производит переадресацию по указанному адресу
	 *
	 * @param string $message Текст сообщения
	 * @param string $redirect Путь для переадресации без siteUrl (если не указан, редирект происходит по рефереру)
	 * @return true
	 */
	
	protected function composeErrorMessage($message = 'При заполнении формы были обнаружены ошибки', $redirect = null) {
		
		$this->_usersession->ErrorMessage = $this->_translate->_($message);
		
		return is_null($redirect) 
				? $this->_redirect($this->_request->getServer('HTTP_REFERER'))
				: $this->_redirect($this->view->siteUrl().$redirect);
		
	}
	
	
}